package org.fioma.tree.suffixTree.memory;

import org.fioma.tree.Node;
import org.fioma.tree.SimpleInternalNode;
import org.fioma.tree.bytes.LabelRefBytesIndex;
import org.fioma.tree.suffixTree.InternalSuffixNode;

public class InternalSuffixNodeMemory<I extends InternalSuffixNodeMemory<I, F>, F extends LeafSuffixNodeMemory<I, F>> extends
		SimpleInternalNode<LabelRefBytesIndex, I, F> implements InternalSuffixNode<LabelRefBytesIndex, I, F>, SuffixNodeMemory<I, F> {

	protected long pos;
	protected SuffixNodeFactoryMemory<L, I, F> memory;

	public InternalSuffixNodeMemory(SuffixNodeFactoryMemory<L, I, F> memory, long pos) {
		super(null, null, null);
		this.pos = pos;
		this.memory = memory;
	}

	@Override
	public I createChildInternalNode(L word) {
		I ret = nodeMemoryFactory.getInternalNode(memory.allocMemoryInternalNode());
		ret.setLabel(word);
		ret.setParent((I) this);
		return ret;
	}

	@Override
	public F createChildLeaf(L word) {
		F ret = nodeMemoryFactory.getLeafNode(memory.allocMemoryLeafNode());
		ret.setLabel(word);
		ret.setParent((I) this);
		return ret;
	}

	@Override
	public SuffixNodeMemory<L, I, F> getChild(byte letter) {
		long childAddress = memory.getChildAddress(pos, letter);
		SuffixNodeMemory<L, I, F> ret;
		if (memory.isLeaf(childAddress)) {
			ret = nodeMemoryFactory.getLeafNode(childAddress);
		} else {
			ret = nodeMemoryFactory.getInternalNode(childAddress);
		}
		return ret;
	}

	@Override
	public void setChild(byte letter, Node<L, I, F> node) {
		memory.setChild(pos, letter, ((SuffixNodeMemory<L, I, F>) node).getPos());
	}

	@Override
	public SuffixNodeMemory<L, I, F>[] getChilds() {
		long[] childsAddresses = memory.getChildsAddresses(pos);
		int length = childsAddresses.length;
		SuffixNodeMemory<L, I, F>[] ret = new SuffixNodeMemory[length];
		long childAddress;
		for (int i = 0; i < length; i++) {
			childAddress = childsAddresses[i];
			if (memory.isLeaf(childAddress)) {
				ret[i] = nodeMemoryFactory.getLeafNode(childAddress);
			} else {
				ret[i] = nodeMemoryFactory.getInternalNode(childAddress);
			}
		}
		return ret;
	}

	@Override
	public I getParent() {
		return nodeMemoryFactory.getInternalNode(memory.getParentAddress(pos));
	}

	@Override
	public void setParent(I parent) {
		memory.setParent(pos, parent.getPos());
	}

	@Override
	public L getLabel() {
		return labelRefBytesRepositry.getLabel(memory.getLabelIndex(pos), memory.getLabelPos(pos), memory.getLabelLength(pos));
	}

	@Override
	public void setLabel(L label) {
		memory.setLabelIndex(pos, label.getIndex());
		memory.setLabelPos(pos, label.getPos());
		memory.setLabelLength(pos, label.getLength());
	}

}
